module axi4_delayer_fifo # (
  parameter DATA_DEPTH = 8,
  parameter DATA_WIDTH = 96
) (
  input  wire clock,
  input  wire reset,
  input  wire ren,
  input  wire wen,
  input  wire [DATA_WIDTH-1:0] wdata,
  output wire [DATA_WIDTH-1:0] rdata,
  output reg  empty,
  output reg  full
);
  localparam POINTER_WIDTH = $clog2(DATA_DEPTH);

  reg [DATA_WIDTH-1:0] fifo [DATA_DEPTH-1:0];
  reg [POINTER_WIDTH-1:0] fifo_head;
  reg [POINTER_WIDTH-1:0] fifo_tail;

  // head pointer
  always @(posedge clock or posedge reset) begin
    if (reset) fifo_head <= 0;
    else if (~empty & ren) fifo_head <= fifo_head + 1;
  end

  // tail pointer
  always @(posedge clock or posedge reset) begin
    if (reset) fifo_tail <= 0;
    else if (~full & wen) fifo_tail <= fifo_tail + 1;
  end

  // write data into fifo
  always @(posedge clock) begin
    if (~full & wen) fifo[fifo_tail] <= wdata;
  end

  assign rdata = (~empty & ren) ? fifo[fifo_head] : 0; // read data from fifo
  assign empty = fifo_head == fifo_tail ? 1'b1 : 1'b0; // flag: empty
  assign full  = (fifo_tail + {{(POINTER_WIDTH -1){1'b0}}, 1'b1}) == fifo_head ? 1'b1 : 1'b0; // flag: full
endmodule
